﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Linq.Expressions;
using Dinamico.Models;
//using Shop.Services.Articles;
using AutoMapper;
using Dinamico.Controllers;
using Dynamico.Service;

namespace Dinamico.Service
{
    public class BasketService : IBasketService
    {
        /// <summary>
        /// Get the List.
        /// </summary>
        public List<BasketArticleModel> List
        {
            get
            {
                var basketList = HttpContext.Current.Session[Const.Session.BasketSessionKey];
                if (basketList != null)
                    return HttpContext.Current.Session[Const.Session.BasketSessionKey] as List<BasketArticleModel>;
                else
                {
                    HttpContext.Current.Session[Const.Session.BasketSessionKey] = new List<BasketArticleModel>();
                    return HttpContext.Current.Session[Const.Session.BasketSessionKey] as List<BasketArticleModel>;
                }
            }
            private set
            {
                if (value == null) throw new ArgumentNullException("Cannot set Basket to NULL. To Clear the Basket, please use RemoveAll().");

                var basketList = HttpContext.Current.Session[Const.Session.BasketSessionKey];
                if (basketList != null) throw new NotSupportedException("User Basket already set in Session");

                HttpContext.Current.Session[Const.Session.BasketSessionKey] = value;
            }
        }

        //IArticleService articleService;

        //public BasketService(IArticleService articleService)
        //{
        //    this.articleService = articleService;
        //}


        private static string GetNewBasketArticleID()
        {
            int basketArticleID = 100000;

            //return System.Guid.NewGuid().ToString();
            //return DateTime.Now.ToString("MMddHHmmssfff");
            if (HttpContext.Current.Session[Const.Session.BasketArticleIDKey] == null)
            {
                HttpContext.Current.Session[Const.Session.BasketArticleIDKey] = basketArticleID;
            }
            else
            {
                basketArticleID = Convert.ToInt32(HttpContext.Current.Session[Const.Session.BasketArticleIDKey].ToString());
                basketArticleID++;
                HttpContext.Current.Session[Const.Session.BasketArticleIDKey] = basketArticleID;
            }

            return basketArticleID.ToString();
        }
        private bool IsValidArticle(int articleId, string articleSizeName)
        {
            //var data = articleService.GetArticleById(articleId);
            //if (data != null)
            //{
            //    bool validSizeName = data.PriceList.Any(_ => _.SizeName.Equals(articleSizeName));

            //    return validSizeName;
            //}

            return false;
        }
        private static bool IsValidQuantity(double quantity)
        {
            return quantity >= 0.01;
        }
        private static void ThrowInvalidArticleException()
        {
            throw new ArgumentException("Invalid article: article not exists in the dataService");
        }
        private static void ThrowInvalidQuantityException()
        {
            throw new ArgumentException("Invalid article.Quantity: it must be greater then 0.01");
        }

        /// <summary>
        /// Get Basket Article by Index.
        /// </summary>
        /// <param name="basketArticleId">Basket Article ID</param>
        /// <returns>BasketArticleModel</returns>
        public BasketArticleModel this[string basketArticleId]
        {
            get
            {
                return List.SingleOrDefault(_ => _.BasketArticleId.Equals(basketArticleId));
            }
        }

        public BasketArticleModel Add(ArticleInputModel article)
        {
            if (article == null) throw new ArgumentException();
            //if (!IsValidArticle(article.ArticleId, article.SizeName)) ThrowInvalidArticleException();
            if (!IsValidQuantity(article.Quantity)) ThrowInvalidQuantityException();

            // *** IF Articles have same IDs and SizeTypes, just summarize the Quantities instead of adding a new object to the list.
            if (!IsEmpty)
            {
                var similarArticle = List.SingleOrDefault(_ => _.Id == article.Id);
                if (similarArticle != null)
                {
                    similarArticle.Quantity += article.Quantity;
                    return similarArticle;
                }
            }


            //*** ELSE Add new Article to the List
            var basketArticle = new BasketArticleModel(article);
            //Generate new Basket Article ID.
            basketArticle.SetBasketArticleId(GetNewBasketArticleID());

            List.Add(basketArticle);

            return basketArticle;
        }


        public void Remove(BasketArticleModel basketArticle)
        {
            if (ContainsArticle(basketArticle.BasketArticleId))
            {
                List.Remove(this[basketArticle.BasketArticleId]);
            }
            else
            {
                throw new ArgumentException("Cannot remove article that doesn't exists on the List");
            }
        }

        public void Update(BasketItemInputModel article)
        {
            if (article == null) throw new ArgumentException();
            if (!IsValidArticle(article.ArticleId,article.SizeName)) ThrowInvalidArticleException();
            if (!IsValidQuantity(article.Quantity)) ThrowInvalidQuantityException();
            // *** IF Articles have same IDs and SizeTypes, just summarize the Quantities instead of adding a new object to the list.
            if (!IsEmpty)
            {
                foreach (BasketArticleModel similarArticle in List)
                {
                    if (similarArticle != null)
                    {
                        if (similarArticle.BasketArticleId.Equals(article.BasketArticleId))
                        {
                            similarArticle.SizeName = article.SizeName;
                            similarArticle.Quantity = article.Quantity;
                        }

                    }
                }
                this.Merge(article);
            }
        }

        public void Merge(BasketItemInputModel article)
        {
            if (article == null) throw new ArgumentException();
            if (!IsValidArticle(article.ArticleId, article.SizeName)) ThrowInvalidArticleException();
            if (!IsValidQuantity(article.Quantity)) ThrowInvalidQuantityException();

            // *** IF Articles have same IDs and SizeTypes, just summarize the Quantities instead of adding a new object to the list.
            if (!IsEmpty)
            {
                //
                bool finded = false;
                foreach (BasketArticleModel similarArticle in List)
                {
                    if (similarArticle != null)
                    {
                        if (!similarArticle.BasketArticleId.Equals(article.BasketArticleId)
                            && similarArticle.Id.Equals(article.ArticleId)
                            //&& similarArticle.SizeName.Equals(article.SizeName)
                            )
                        {

                            if (similarArticle != null)
                            {
                                similarArticle.Quantity += article.Quantity;
                                finded = true;
                                break;
                            }
                        }
                    }
                }
                if (finded)
                {
                    if (ContainsArticle(article.BasketArticleId))
                    {
                        List.Remove(this[article.BasketArticleId]);

                    }
                }
            }
        }

        public void RemoveAll()
        {
            if (!IsEmpty)
            {
                List.Clear();
            }
        }

        public void RemoveById(string basketArticleId)
        {
            if (ContainsArticle(basketArticleId))
            {
                List.Remove(this[basketArticleId]);
            }
        }

        public void UpdateQuantity(BasketArticleModel basketArticle)
        {
            if (ContainsArticle(basketArticle.BasketArticleId))
            {
                var article = this[basketArticle.BasketArticleId];

                if (IsValidQuantity(basketArticle.Quantity))
                    article.Quantity = basketArticle.Quantity;
                else
                    ThrowInvalidQuantityException();
            }
        }

        public bool IsEmpty
        {
            get { return !List.Any(); }
        }

        public bool ContainsArticle(string basketArticleId)
        {
            if (!IsEmpty)
            {
                return List.Any(_ => _.BasketArticleId.Equals(basketArticleId));
            }
            return false;
        }

        public List<BasketItemModel> BasketListToBasketItemModels()
        {
            List<BasketItemModel> resultsList = new List<BasketItemModel>();

            if (!this.IsEmpty)
            {
                var basketList = this.List.OrderByDescending(_ => _.BasketArticleId);
                foreach (var item in basketList)
                {
                    //Add top basket
                    var gproduct = N2.Find.Items
                        .Where.ID.Eq(Convert.ToInt32(item.Id))
                        .Select().SingleOrDefault();
                    var basketItem = ConvertArticle(gproduct as PartProductGoogleModel);

                    basketItem.Quantity =  item.Quantity;
                    basketItem.BasketArticleId = item.BasketArticleId;

                    if (gproduct is PartProductGoogleModel)
                    {
                        resultsList.Add(basketItem);
                   }
                }
            }
            return resultsList;
        }

        public static BasketItemModel ConvertArticle(PartProductGoogleModel gProd)
        {
            var basketItem = new BasketItemModel();

            basketItem.Id = Convert.ToString(gProd.ID);
            basketItem.Name = gProd.Gname;

            basketItem.Identifier = gProd.Identifier;
            if (String.IsNullOrEmpty(gProd.Identifier))
            {
                basketItem.Identifier = String.Empty;
            }

            basketItem.Brand = gProd.Brand;
            if (String.IsNullOrEmpty(gProd.Brand))
            {
                basketItem.Brand = String.Empty;
            }

            basketItem.Description = gProd.Description;
            if (String.IsNullOrEmpty(gProd.Description))
            {
                basketItem.Description = String.Empty;
            }

            basketItem.IdentifierType = gProd.IdentifierType;
            if (String.IsNullOrEmpty(gProd.IdentifierType))
            {
                basketItem.IdentifierType = String.Empty;
            }

            basketItem.Url = gProd.Parent.Url;

            basketItem.NameShort = gProd.Gname;
            if (String.IsNullOrEmpty(gProd.Gname))
            {
                basketItem.NameShort = String.Empty;
            }

            //todo
            var no_image = "/upload/n2logo.png";

            basketItem.ThumbnailPath = gProd.Image;
            if (string.IsNullOrEmpty(basketItem.ThumbnailPath)) {
                basketItem.ThumbnailPath = no_image;
            }

            basketItem.Image2 = gProd.Image2;
            if (string.IsNullOrEmpty(basketItem.Image2))
            {
                basketItem.Image2 = no_image;
            }

            basketItem.Image3 = gProd.Image3;
            if (string.IsNullOrEmpty(basketItem.Image3))
            {
                basketItem.Image3 = no_image;
            }
            

            var priceses = Utils.GetTopFlourPrice(gProd.CurrentPrice);

            basketItem.Price = Convert.ToDouble(priceses[0]);
            basketItem.PriceTop = priceses[1];
            basketItem.PriceFloor = priceses[2];

            return basketItem;
        }

    }
}
